package com.ptu.server.Impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ptu.config.RabbitMQConfig;
import com.ptu.entity.SeckillOrder;
import com.ptu.entity.SeckillProduct;
import com.ptu.mapper.SeckillOrderMapper;
import com.ptu.mapper.SeckillProductMapper;
import com.ptu.server.SeckillOrderServer;
import com.ptu.util.PageResult;
import com.ptu.util.Result;
import com.ptu.util.UserHolder;
import com.ptu.vo.SeckillOrderVO;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;

@Service
public class SeckillOrderServerImpl implements SeckillOrderServer {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    // 秒杀优惠券Lua脚本
    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }

    @Autowired
    private SeckillProductMapper seckillProductMapper;

    /**
     * 秒杀
     * @param productId
     * @return
     */
    @Override
    public Result<Void> add(Long productId) {
        System.out.println("添加秒杀订单");
        Long userId = Long.valueOf(UserHolder.getUser().getId());

        //获取商品name
        SeckillProduct seckillProduct = seckillProductMapper.getDetailById(productId);
        //String name = seckillProduct.getName();
        //添加秒杀订单
        //1.  调用Lua脚本
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                seckillProduct.getName(),       // ARGV[1] -> 商品名称（String）
                userId.toString());     // ARGV[2] -> 用户ID（String）

        //2.判断结果为0
        int r = result.intValue();
        if (r != 0){
            //2.1不为0，返回错误信息,代表 没有购买
            return Result.error(r == 1 ? "库存不足" : "不能重复下单");
        }

        System.out.println("秒杀成功");
        //3.创建订单对象
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setProductId(productId);
        seckillOrder.setUserId(userId);

        System.out.println("创建订单对象" + seckillOrder);
        //4.发送消息到RabbitMQ保存订单，扣减库存
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.SECKILL_ORDER_EXCHANGE,
                RabbitMQConfig.SECKILL_ORDER_ROUTING_KEY,
                seckillOrder
        );


        return Result.success();
    }

    @Transactional
    @Override
    public void handleVoucherOrder(SeckillOrder seckillOrder) {
        Long userId = seckillOrder.getUserId();

        //尝试创建锁对象
        RLock lock = redissonClient.getLock("lock:order:" + userId);
        //获取锁
        boolean isLock = lock.tryLock();
        System.out.println("获取锁," + isLock);
        //获取锁失败，直接返回失败或者重试
        if (!isLock) {
            System.out.println("同一个用户只能购买一次");
            return;
        }
        try {
            //获取锁成功，创建订单
            createSeckillOrder(seckillOrder);
        } finally {
            //释放锁
            lock.unlock();
        }
    }


    @Transactional
    public void createSeckillOrder(SeckillOrder seckillOrder) {
        Long userId = seckillOrder.getUserId();

        //乐观锁查询订单
        int num = seckillOrderMapper.getByUserIdAndProductId(userId, seckillOrder.getProductId());

        if (num > 0) {
            //用户已经购买过了
            System.out.println("用户已经购买过一次！");
            return;
        }

        //扣减库存
        boolean success = seckillProductMapper.deductStock(seckillOrder.getProductId());

        if (!success) {
            //扣减失败
            System.out.println("库存不足！");
            return;
        }

        SeckillProduct  seckillProduct = seckillProductMapper.getDetailById(seckillOrder.getProductId());
        seckillOrder.setName(seckillProduct.getName());
        seckillOrder.setPrice(seckillProduct.getPrice());
        seckillOrder.setStatus(0);

        seckillOrderMapper.add(seckillOrder);
    }

    /**
     * 取消订单
     * @param id
     * @return
     */
    @Transactional
    @Override
    public void cancel(Long id) {
        //恢复库存
        SeckillOrder seckillOrder = seckillOrderMapper.detail(id);
        SeckillProduct product = seckillProductMapper.getDetailById(seckillOrder.getProductId());
        //恢复数据库库存
        seckillProductMapper.resumeStock(product.getId());

        //恢复redis库存
        // 3. 恢复 Redis 库存（原子操作）
        String stockKey = "seckill:stock:" + product.getName(); // Key 必须与下单时一致！
        stringRedisTemplate.opsForValue().increment(stockKey, 1); // +1

        // 4. 移除用户购买标记（允许用户再次购买）
        String userKey = "seckill:user:" + product.getName();
        stringRedisTemplate.opsForSet().remove(userKey, seckillOrder.getUserId().toString());

        seckillOrderMapper.cancleById(id);
    }

    // 用户退款
    @Override
    public void refund(Long id) {
        seckillOrderMapper.updateStatusByIdAndStatus(id, 6);
    }

    // 支付
    @Override
    public void pay(Long id) {
        seckillOrderMapper.updateStatusByIdAndStatus(id, 1);
    }

    //  完成
    @Override
    public void complete(Long id) {
        seckillOrderMapper.updateStatusByIdAndStatus(id, 4);
    }

    // 管理员获取订单列表
    @Override
    public PageResult getList(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<SeckillOrder> page = seckillOrderMapper.list();
        return new PageResult(page.getTotal(), page.getResult());
    }

    //  秒杀商品发货
    @Override
    public void deliver(Long id) {
        seckillOrderMapper.updateStatusByIdAndStatus(id, 3);
    }

    //  管理员退款
    @Override
    public void adminRefund(Long id) {
        seckillOrderMapper.updateStatusByIdAndStatus(id, 5);
    }

    //  用户获取秒杀订单列表
    @Override
    public List<SeckillOrderVO> list() {
        System.out.println("用户获取秒杀订单列表");
        Integer userId = UserHolder.getUser().getId();

        List<SeckillOrderVO> seckillOrderVOS = seckillOrderMapper.userGetList(userId);

        return seckillOrderVOS;
    }


}
